package net.udp;

import java.io.IOException;
import java.net.*;
import java.util.Arrays;
import java.util.Objects;

/**
 * 客户端udp连接演示
 * @author fidel
 */
public class ClientDemo {
    public static void main(String[] args) throws IOException {
        // 创建一个数据包套接字（DatagramSocket）实例并绑定本地主机的指定端口
        DatagramSocket datagramSocket = new DatagramSocket(18723);
        // 将数据包套接字连接到指定地址的端口号
        datagramSocket.connect(InetAddress.getLocalHost(), 18722);
        String message = "用户数据报协议（UDP）的定义是为了在一组计算机网络相互连接的环境中，提供一种数据报模式的分组交换计算机通信。该协议假设使用互联网协议（IP）作为基础协议。";
        // 使用UTF-8字符集将此字符串编码为一个字节序列，并将结果存储到一个新的字节数组中
        byte[] arr = message.getBytes("UTF-8");
        int count = arr.length;
        // 数组长度的常量值
        final int len = 16;
        final byte[] buf = new byte[len];
        /*
         * int值占据4个字节的内存空间
         * 将int值向右移动24位，右侧的24位（int值的第二、三、四字节）被移出
         * 强制转换为byte值后，int值的第一个字节由byte引用
         */
        buf[0] = (byte) (count >> 24);
        /*
         * 将int值向右移动16位，右侧的16位（int值的第三、四个字节）被移出
         * 强制转换为byte值后，int值的第二个字节由byte引用
         */
        buf[1] = (byte) (count >> 16);
        /*
         * 将int值向右移动8位，右侧的8位（int值的第四个字节）被移出
         * 强制转换为byte值后，int值的第三个字节由byte引用
         */
        buf[2] = (byte) (count >> 8);
        // 强制转换为byte值后，int值的最后一个字节由byte引用
        buf[3] = (byte) count;
        DatagramPacket datagramPacket = new DatagramPacket(buf, 4);
        // 从这个数据包套接字发送一个数据包
        datagramSocket.send(datagramPacket);
        datagramPacket = new DatagramPacket(buf, len);
        int seq = 0;
        while (count > 0) {
            if (count > len) {
                // 拷贝数组的指定区间到一个新数组中，长度为len
                byte[] range = Arrays.copyOfRange(arr, seq * len, (seq + 1) * len);
                datagramPacket = new DatagramPacket(range, len);
                datagramSocket.send(datagramPacket);
                count -= len;
            } else {
                byte[] range = Arrays.copyOfRange(arr, seq * len, seq * len + count);
                datagramPacket = new DatagramPacket(range, count);
                datagramSocket.send(datagramPacket);
                count = 0;
            }
            seq++;
        }
        // 重新实例化数据包后，方可接收数据包
        datagramPacket = new DatagramPacket(buf, len);
        // 从此数据包套接字接收一个数据包
        datagramSocket.receive(datagramPacket);
        int val1 = buf[3] & 0xff;
        int val2 = (buf[2] & 0xff) << 8;
        int val3 = (buf[1] & 0xff) << 16;
        int val4 = (buf[0] & 0xff) << 24;
        count = val1 | val2 | val3 | val4;
        datagramPacket.setLength(len);
        seq = 0;
        arr = null;
        byte[] src = arr;
        while (count > 0) {
            // 重新构造arr时对其扩容
            arr = new byte[len * (seq + 1)];
            // 如果src的引用（数组对象）不为空
            if (Objects.nonNull(src)) {
                System.arraycopy(src, 0, arr, 0, src.length);
            }
            datagramSocket.receive(datagramPacket);
            if (count > len) {
                System.arraycopy(buf, 0, arr, arr.length - len, len);
                count -= len;
            } else {
                System.arraycopy(buf, 0, arr, arr.length - len, count);
                count = 0;
            }
            // 将src的引用（数组对象）指向arr的引用（数组对象）
            src = arr;
            seq++;
        }
        message = new String(arr, "UTF-8");
        System.out.println(message);
        datagramSocket.close();
    }
}
